package com.lancoo.ccas52.service.mobileService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.ccas52.entity.*;
import com.lancoo.ccas52.exception.BizException;
import com.lancoo.ccas52.mapper.*;
import com.lancoo.ccas52.pojo.common.PageInfo;
import com.lancoo.ccas52.pojo.constant.GlobalConstant;
import com.lancoo.ccas52.pojo.dto.CourseTypeStatisticsDto;
import com.lancoo.ccas52.pojo.dto.RedisStudentOptionalClass;
import com.lancoo.ccas52.pojo.dto.ScheduleDto;
import com.lancoo.ccas52.pojo.response.basicPlatform.BaseStudent;
import com.lancoo.ccas52.pojo.vo.*;
import com.lancoo.ccas52.redis.RedisMQPublisher;
import com.lancoo.ccas52.service.*;
import com.lancoo.ccas52.service.impl.StudentServiceImpl;
import com.lancoo.ccas52.util.BatchInsert;
import com.lancoo.ccas52.util.ExcelFormatUtil;
import com.lancoo.ccas52.util.PagingUtil;
import com.lancoo.ccas52.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 选课移动端
 * </p>
 *
 * @author pengrui
 * @since 2023/7/6
 */
@Service
@Slf4j
public class MobileStudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements MobileStudentService {

    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private TeacherService teacherService;
    @Resource
    private CssTaskInfoService cssTaskInfoService;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private TeachingClassWeekService teachingClassWeekService;
    @Resource
    private CssRangeService cssRangeService;
    @Resource
    private CssTaskRoundService cssTaskRoundService;
    @Resource
    private PlanTeachingService planTeachingService;

    @Resource
    private StudentMapper studentMapper;
    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private MajorMapper majorMapper;
    @Resource
    private TeachingClassStudentMapper teachingClassStudentMapper;
    @Resource
    private PlanTeachingMapper planTeachingMapper;
    @Resource
    private PlanTeachingStudentMapper planTeachingStudentMapper;
    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private CssProhibitStudentMapper cssProhibitStudentMapper;

    @Resource
    private RedisMQPublisher redisMQPublisher;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private StudentService studentService;

    @Autowired
    private StudentServiceImpl studentServiceimpl;



    @Resource
    private CourseMapper courseMapper;

    @Resource
    private SegmentMapper segmentMapper;




    @Override
    public List<StudentTeachingClass> getSelectedByStudentId(Integer taskId, Long studentId, Integer teachingClassType, Integer studyNature) {

        //已选教学班 包括0全部 1主修 2辅修

        List<StudentTeachingClass> mergedList = studentService.getSelectedByStudentId(taskId,studentId,teachingClassType);
        if(studyNature==0){
            return  mergedList;
        }else{
            mergedList = mergedList.stream().filter(a -> a.getStudyNature() == studyNature).collect(Collectors.toList());
        }
        return mergedList;
    }


    @Override
    public SelectedCourseStatistics getStudentSelectedCourseStatisticsByStudentId (Integer taskId, Long studentId, Integer teachingClassType) {
        //获取学生都有哪些教学班
        List<StudentTeachingClass> teachingClassList = studentService.getSelectedByStudentId(taskId,studentId,teachingClassType);
        teachingClassList=teachingClassList.stream().filter(a->a.getTeachingClassType()!=0).collect(Collectors.toList());
        SelectedCourseStatistics result = new SelectedCourseStatistics();
        result.setCourseNum(teachingClassList.size());
        Double totalCredits = teachingClassList.stream()
                .mapToDouble(StudentTeachingClass::getCredit)
                .sum();
        result.setCreditNum(totalCredits);

        List<CourseTypeStatisticsDto>list =new ArrayList<>();


        Map<String, Map<Integer, List<StudentTeachingClass>>> typeCounts = teachingClassList.stream()
                .collect(Collectors.groupingBy(StudentTeachingClass::getCourseTypeId,
                        Collectors.groupingBy(StudentTeachingClass::getStudyNature)));

        for (Map.Entry< String, Map<Integer, List<StudentTeachingClass>> > entryCourseType : typeCounts.entrySet()){
            String courseTypeId =entryCourseType.getKey();
            CourseTypeStatisticsDto dto = new CourseTypeStatisticsDto();
            for (Map.Entry< Integer, List<StudentTeachingClass>> entryStudyNature : entryCourseType.getValue().entrySet()){
                int studyNature = entryStudyNature.getKey();
                if(studyNature==1){
                    dto.setCourseTypeId(courseTypeId);
                    StudentTeachingClass teachingClass = entryStudyNature.getValue().get(0);
                    dto.setCourseType(teachingClass.getCourseType());
                    dto.setMajorCourseNum(entryStudyNature.getValue().size());
                }else {
                    dto.setCourseTypeId(courseTypeId);
                    StudentTeachingClass teachingClass = entryStudyNature.getValue().get(0);
                    dto.setCourseType(teachingClass.getCourseType());
                    dto.setMajorCourseNum(entryStudyNature.getValue().size());
                }
            }
            list.add(dto);
        }
        result.setCourseTypeStatistics(list);
        return result;

    }
    @Override
    public SelectedCourseStatistics getCourseAndCreditStatistics (Integer taskId, Long studentId, Integer teachingClassType) {
        Student student = this.getById(studentId);
        //已选教学班 包括0全部 1主修 2辅修

        List<StudentTeachingClass> courseStatisticsList  = studentService.getSelectedByStudentId(taskId,studentId,teachingClassType);

        courseStatisticsList=courseStatisticsList.stream().filter(a->a.getTeachingClassType()!=0).collect(Collectors.toList());
        SelectedCourseStatistics result =new SelectedCourseStatistics();
        result.setCourseNum(courseStatisticsList.size());
        Double totalCredits = courseStatisticsList.stream()
                .mapToDouble(StudentTeachingClass::getCredit)
                .sum();
        result.setCreditNum(totalCredits);
        return result;
    }

    //获取教学班详细信息（课程+环节）
    public List<StudentTeachingClass> getTeachingClassDetail(Integer taskId, List<Long> teachingClassIds) {
        List<StudentTeachingClass> list = new ArrayList<>();
        if (CollUtil.isEmpty(teachingClassIds)) {
            return list;
        }
        redisUtil.hgets(studentServiceimpl.getCacheKeys(taskId, null, 6, null), teachingClassIds.stream().map(String::valueOf).collect(Collectors.toSet()))
                .forEach(a -> {
                    if (a != null) {
                        list.add((StudentTeachingClass) a);
                    }
                });

        for (StudentTeachingClass teachingClass:list) {
            teachingClass.setCourseOrSegment(teachingClassService.getById(teachingClass.getTeachingClassId()).getFlag());
        }
        //redis 不存在的数据则查询数据库并缓存
        teachingClassIds.removeAll(list.stream().map(StudentTeachingClass::getTeachingClassId).collect(Collectors.toList()));
        if (CollUtil.isNotEmpty(teachingClassIds)) {
            //课程
            List<StudentTeachingClass> courseTeachingClass = studentMapper.getNormalCourseTeachingClass(teachingClassIds, null);
            //环节
            List<StudentTeachingClass> segmentTeachingClass = studentMapper.getNormalSegmentTeachingClass(teachingClassIds);
            courseTeachingClass.addAll(segmentTeachingClass);

            //填充教师信息
            Map<Long, List<Teacher>> teacherMap = teacherService.getTeacherByTeachingClassIds(teachingClassIds).stream()
                    .collect(Collectors.groupingBy(Teacher::getTeachingClassId));
            //课表信息
            List<ScheduleDto> scheduleDtoList = scheduleMapper.getScheduleByTeachingClassIds(null, teachingClassIds);
            Map<Long, List<ScheduleDto>> scheduleMap = scheduleDtoList.stream().collect(Collectors.groupingBy(ScheduleDto::getTeachingClassId));
            //学生人数
            Map<Long, Integer> studentNumMap = teachingClassStudentMapper.getStudentNumber(teachingClassIds)
                    .stream().collect(Collectors.toMap(TeachingClassCourseDto::getTeachingClassId, TeachingClassCourseDto::getStudentNumber));
            courseTeachingClass.forEach(a -> {
                a.setTeachers(teacherMap.get(a.getTeachingClassId()));
                a.setSchedules(scheduleMap.get(a.getTeachingClassId()));
                //学生人数
                a.setStudentNumber(studentNumMap.getOrDefault(a.getTeachingClassId(), 0));
            });
            list.addAll(courseTeachingClass);
            //缓存数据
            if (CollUtil.isNotEmpty(courseTeachingClass)) {
                redisUtil.hmset(studentServiceimpl.getCacheKeys(taskId, null, 6, null), courseTeachingClass.stream().collect(Collectors.toMap(a -> a.getTeachingClassId(), a -> a)), 60 * 60 * 24 * 7);
            }
        }
        return list;
    }


    @Override
    public StudentTeachingClass getCourseDetail(Integer taskId, Long studentId, Integer teachingClassType, Long teachingClassId) {
        List<Long> classIds = new ArrayList<>();
         classIds.add(teachingClassId);
        List<StudentTeachingClass>  teachingDetail = getTeachingClassDetail(taskId,classIds);
        teachingDetail=teachingDetail.stream()
                .filter(detail -> detail.getTeachingClassType() == teachingClassType )
                .collect(Collectors.toList());

        if(teachingDetail.size()==0){
            return null;
        }
        for (StudentTeachingClass teachingClass :teachingDetail) {
            if(teachingClass.getCourseOrSegment()==1){
                Course course = courseMapper.selectById(teachingClass.getCourseId());
                teachingClass.setComputerHour(course.getComputerHour());
                teachingClass.setExperimentalHour(course.getExperimentalHour());
                teachingClass.setLectureHour(course.getLectureHour());
                teachingClass.setOtherHour(course.getOtherHour());
                if(course.getDescription()==null){
                    teachingClass.setDescription("");
                }else {
                    teachingClass.setDescription(course.getDescription());
                }
            }else if(teachingClass.getCourseOrSegment()==2){
                Segment segment=segmentMapper.selectById(teachingClass.getCourseId());
                if(segment.getDescription()==null){
                    teachingClass.setDescription("");
                }else {
                    teachingClass.setDescription(segment.getDescription());
                }
            }
            String redisKey =studentServiceimpl.getCacheKeys(taskId, null, 3, null);
            if (redisUtil.hHasKey(redisKey, studentId + "-" + teachingClassId)) {
                TeachingClassStudent tcs=(TeachingClassStudent)redisUtil.hget(redisKey, studentId + "-" + teachingClassId);
                teachingClass.setFlag(tcs.getFlag());
            }else{
                TeachingClassStudent teachingClassStudent= teachingClassStudentMapper.selectOne(new LambdaQueryWrapper<TeachingClassStudent>()
                        .eq(TeachingClassStudent ::getStudentId,studentId)
                        .eq(TeachingClassStudent ::getTeachingClassId ,teachingClass.getTeachingClassId()));
                if(teachingClassStudent!=null){
                    redisUtil.hset(studentServiceimpl.getCacheKeys(taskId, null, 3, null), studentId + "-" + teachingClassId, teachingClassStudent);
                    teachingClass.setFlag(teachingClassStudent.getFlag());
                }
            }
        }

        return teachingDetail.get(0);
    }

    @Override
    public Integer getCanceledCourseNum( Integer taskId, Integer teachingClassType, Long studentId ){
        int res=0;
        Student student=studentMapper.selectOne(new LambdaQueryWrapper<Student>().eq(Student ::getStudentId,studentId));
        HashMap<Long, RedisStudentOptionalClass>map=studentServiceimpl.getAvailableTeachingClass(taskId,teachingClassType,student);
        List<Long> ids=map.values().stream().map(RedisStudentOptionalClass::getTeachingClassId).collect(Collectors.toList());
        String redisKey =studentServiceimpl.getCacheKeys(taskId, null, 3, null);
        for (Long id:ids) {
            if (redisUtil.hHasKey(redisKey, studentId + "-" + id)) {
                TeachingClassStudent tcs=(TeachingClassStudent)redisUtil.hget(redisKey, studentId + "-" + id);
                if ( tcs.getFlag()==2||tcs.getFlag()==3){
                    res++;
                }
            }else{
                TeachingClassStudent tcs= teachingClassStudentMapper.selectOne(new LambdaQueryWrapper<TeachingClassStudent>()
                        .eq(TeachingClassStudent ::getStudentId,studentId)
                        .eq(TeachingClassStudent ::getTeachingClassId ,id));
                if( tcs!=null){
                    redisUtil.hset(redisKey, studentId + "-" + id, tcs);
                    if ( tcs.getFlag()==2||tcs.getFlag()==3){
                        res++;
                    }
                }
            }
        }
        return  res;
    }

//    @Override
//    public List<StudentTeachingClass> getStudentCourseTableByStudentId(Integer taskId, Long studentId, Integer teachingClassType) {
//        Student student = this.getById(studentId);
//        //已选教学班 包括主修 辅修
//        List<StudentTeachingClass> mergedList = Stream.of(studentServiceimpl.getAvailableTeachingClass(taskId, teachingClassType, 1, student).values(),
//                studentServiceimpl.getAvailableTeachingClass(taskId, teachingClassType, 2, student).values())
//                .flatMap(Collection::stream)
//                .filter(a -> ObjUtil.isNotNull(a.getFlag()) && a.getFlag() == 1)
//                .collect(Collectors.toList());
//        //环节教学班 非在线选课教学班
//        mergedList.addAll( studentServiceimpl.getNormalTeachingClass(taskId, studentId));
//        return mergedList;
//    }



}
































